package br.unisinos.aidk.puzzle;

import java.util.LinkedList;

import br.unisinos.aidk.graph.Node;
import br.unisinos.aidk.graph.Problem;

public class EightBoardProblem extends Problem<EightBoard> {

	private static int ref[][] = {{1,2,3},{4,5,6},{7,8,0}};
	
	@Override
	public LinkedList<Node<EightBoard>> expand(Node<EightBoard> node) {
		EightBoard b = node.getValue();
		LinkedList<Node<EightBoard>> list = new LinkedList<Node<EightBoard>>();
		int board[][] = b.board;
		for(int i=0; i<board.length; i++){
			for(int j=0; j<board[i].length; j++){
				for(int p=0; p<4; p++){
					int x=0, y=0;
					switch(p){
						case 0: x = -1;
							break;
						case 1: y = -1;
							break;
						case 2: x = 1;
							break;
						case 3: y = 1;
							break;							
					}
					if(i+y>=0 && j+x>=0 && i+y<3 && j+x<3){
						if(b.isEmpty(i+y, j+x)){
							EightBoard c = b.copy();
							c.move(i, j, i+y, j+x);
							System.out.println(c);
				
							Node<EightBoard> nn = new Node<EightBoard>();							
							String op = i+","+j+","+(i+y)+","+(j+x);
							nn.setOperator(op);
							nn.setParent(node);
							nn.setDepth(node.getDepth()+1);
							nn.setValue(c);
							if(!foo(nn)){
								list.add(nn);	
							}							
						}
					}
				}
			}
		}
		return list;
	}

	private boolean foo(Node<EightBoard> tmp) {
		String t = tmp.getOperator(); 
		while(!t.equals(".")){
			tmp = tmp.getParent();
			if(t.equals(tmp.getOperator())){
				return true;
			}
			t = tmp.getOperator();
		}
		return false;
	}

	@Override
	public boolean isGoal(EightBoard b) {
		int board[][] = b.board;
		for(int i=0; i<board.length; i++){
			for(int j=0; j<board[i].length; j++){				
				if(board[i][j]!=ref[i][j]){
					return false;
				}
			}
		}
		return true;
	}
	
	public static float evaluate(EightBoard b){
		int board[][] = b.board;
		int sum = 0;
		for(int i=0; i<board.length; i++){
			for(int j=0; j<board[i].length; j++){				
				sum += (board[i][j]-ref[i][j])^2;
			}
		}
		return (float)Math.sqrt(sum);		
	}

}
